package com.atguigu.spzx.manager.service.impl;

import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSON;
import com.atguigu.spzx.common.exception.GuiguException;
import com.atguigu.spzx.manager.mapper.SysUserMapper;
import com.atguigu.spzx.manager.service.SysUserService;
import com.atguigu.spzx.model.dto.system.SysUserDto;
import com.atguigu.spzx.model.entity.system.SysUser;
import com.atguigu.spzx.model.vo.common.ResultCodeEnum;
import com.atguigu.spzx.model.dto.system.LoginDto;
import com.atguigu.spzx.model.vo.system.LoginVo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class SysUserServiceImpl implements SysUserService {
    @Resource
    SysUserMapper sysUserMapper;


//    @Resource   可以用来在redis中存储对象  自定义类型的类 需要实现序列化接口
//    RedisTemplate
    @Resource  //主要用来存储字符串，也可以将对象转为json字符串存储
    StringRedisTemplate stringRedisTemplate;
    @Override
    public LoginVo login(LoginDto loginDto) {
        //1、参数不能为空
        String userName = loginDto.getUserName();
        String inputPassword = loginDto.getPassword();
        String code = loginDto.getCode();
        String codeKey = loginDto.getCodeKey();
        if(!StringUtils.hasLength(userName)||
                !StringUtils.hasLength(inputPassword)||
                !StringUtils.hasLength(code)||
                !StringUtils.hasLength(codeKey)
        ){
            //异常处理器 捕获到异常后 无法判断需要返回的Result对象的 code值 message值..
            //自定义异常类：对异常进行扩展 类中定义 code  message传递需要异常处理器创建的Result对象的 code值 message值
//            throw new RuntimeException("登录参数错误");
            throw new GuiguException(ResultCodeEnum.UNKNOW_ERROR);
        }
        //校验验证码是否正确：避免恶意攻击
        String redisCode = stringRedisTemplate.opsForValue().get("user:login:code:"+codeKey);
        if(!StringUtils.hasLength(redisCode)  || !redisCode.equals(code)){
//            throw new RuntimeException("验证码错误");
            throw new GuiguException(ResultCodeEnum.LOGIN_CODE_ERROR);
        }


        //2、根据账号查询会员
        SysUser sysUser = sysUserMapper.selectByUserName(userName);
        if(sysUser==null){
//            throw new RuntimeException("账号不存在");
            throw new GuiguException(ResultCodeEnum.LOGIN_USERNAME_ERROR);
        }
        //3、校验密码
        //加密明文密码和数据库查询到的加过密的密码比较： md5加密
        String encodePwd = DigestUtils.md5DigestAsHex(inputPassword.getBytes());
        if(!encodePwd.equals(sysUser.getPassword())){
//            throw new RuntimeException("密码错误");
            throw new GuiguException(ResultCodeEnum.LOGIN_PASSWORD_ERROR);
        }
        //4、保存登录成功的数据到redis中：保持登录状态(过期时间 30min)
        //UUID作为key 比较长：占用redis内存空间
        String uuid = UUID.randomUUID().toString().replace("-", "");
        stringRedisTemplate.opsForValue().set("user:login:"+uuid,JSON.toJSONString(sysUser),
                600, TimeUnit.MINUTES);
        //5、返回前端需要的Vo对象：token  refresh_token
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(uuid); //将登录状态的token交给前端
        loginVo.setRefresh_token("");

        //删除使用过的验证码
        stringRedisTemplate.delete("user:login:code:"+codeKey);
        return loginVo;
    }

    @Override
    public SysUser getUserInfo(String token) {
        String json = stringRedisTemplate.opsForValue().get("user:login:" + token);
        if(!StringUtils.hasLength(json)){
            throw new GuiguException(ResultCodeEnum.LOGIN_STATUS_ERROR);
        }
        return JSON.parseObject(json,SysUser.class);
    }

    @Override
    public void logout(String token) {
        stringRedisTemplate.delete("user:login:" + token);
    }

    @Override
    public PageInfo<SysUser> page(Integer pageNum, Integer pageSize, SysUserDto sysUserDto) {
        //开启分页查询
        PageHelper.startPage(pageNum,pageSize,true,true,null);
        //mapper中自定义sql
        // sysUserMapper 操作的是sys_user表，查询到的数据 一般封装表映射的实体类对象
        List<SysUser> sysUsers = sysUserMapper.selectPage(sysUserDto);
        //封装分页对象数据返回
        return new PageInfo<SysUser>(sysUsers);
    }

    @Override
    public void deleteById(Long id) {
        sysUserMapper.deleteById(id);
    }

    @Override
    public void save(SysUser sysUser) {
        if(!StringUtils.hasLength(sysUser.getUserName())||
                !StringUtils.hasLength(sysUser.getPassword())){
            throw new GuiguException(ResultCodeEnum.LOGIN_PARAMS_ERROR);
        }
        //时间
        sysUser.setCreateTime(new Date());
        sysUser.setUpdateTime(new Date());
        //密码加密：   必须使用登录时密码校验时使用的加密算法
        sysUser.setPassword(DigestUtils.md5DigestAsHex(sysUser.getPassword().getBytes()));
        sysUserMapper.save(sysUser);
    }

    @Override
    public SysUser getById(Long id) {
        return sysUserMapper.getById(id);
    }

    @Override
    public void updateById(SysUser sysUser) {
        sysUser.setUpdateTime(new Date());
        sysUserMapper.updateById(sysUser);
    }
}
